
import 'dart:async';
import 'dart:convert';

import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart';

class Crypto {
  static MethodChannel? _channel;

  static String MD5(String? string) {
    if(isEmpty(string)) return "";
    var bytes = utf8.encode(string!); // data being hashed
    var digest = md5.convert(bytes);
    return digest.toString();
  }

  static String HmacSHA256(String? string, String key, {bool hex = true}) {
    if(isEmpty(string)) return "";

    var kkey = utf8.encode(key);
    var bytes = utf8.encode(string!);

    var hmacSha256 = Hmac(sha256, kkey); // HMAC-SHA256
    var digest = hmacSha256.convert(bytes);
    if(hex) return digest.toString();
    return const Base64Encoder().convert(digest.bytes);
  }

  ///计算字符串 [string] 的 sha256
  static String SHA256(String? string) {
    if(isEmpty(string)) return "";
    var bytes = utf8.encode(string!); // data being hashed
    var digest = sha256.convert(bytes);
    return digest.toString();
  }

  ///计算字符串 [string] 的sha256
  static Future<String> sha256String(String? string) async {
    if(isEmpty(string)) return "";
    return await _get().invokeMethod('sha256String', string);
  }

  ///计算文件的sha256<br>
  ///[filePath]文件路径<br>
  ///[lowerCase] 预留字段<br>
  static Future<String> sha256File(String? filePath, {bool lowerCase = true}) async {
    if(isEmpty(filePath)) return "";
    return await _get().invokeMethod('sha256File', filePath);
  }

  ///base64加密
  static String encodebase64(String? content) {
    if(isEmpty(content)) return "";
    var d = utf8.encode(content!);
    return base64Encode(d);
  }

  ///base64解密
  static String decodebase64(String? content) {
    if(isEmpty(content)) return "";
    return String.fromCharCodes(base64Decode(content!));
  }

  ///计算字符串 [string] 的MD5
  static Future<String> md5String(String? string) async {
    if(isEmpty(string)) return "";
    return await _get().invokeMethod('md5String', string);
  }

  ///计算文件的MD5<br>
  ///[filePath]文件路径<br>
  ///[lowerCase] 预留字段<br>
  static Future<String> md5File(String? filePath, {bool lowerCase = true}) async {
    if(isEmpty(filePath)) return "";
    return await _get().invokeMethod('md5File', filePath);
  }

  ///计算byte数组的MD5
  static Future<String> md5Bytes(Uint8List data) async {
    return await _get().invokeMethod('md5Byte', data);
  }

  ///[Deprecated] ios 未实现aes gcm的算法
  ///使用aes算法加密字符串[content]，[password]为密钥，
  ///[hex]设置输出格式为hex或base64
  static Future<String> aesEncrypt(String? content, String password, {bool hex = true}) async {
    if(isEmpty(content) || isEmpty(password)) return "";
    return await _get().invokeMethod('aesEncrypt', {"content" : content, "password" : password, "hex" : hex});
  }

  ///使用aes算法解密字符串[content]，[password]为密钥，
  ///[hex]字符串格式为hex或base64
  static Future<String> aesDecrypt(String? content, String password, {bool hex = true}) async {
    if(isEmpty(content) || isEmpty(password)) return "";
    return await _get().invokeMethod('aesDecrypt', {"content" : content, "password" : password, "hex" : hex});
  }

  ///使用HmacSHA256算法加密字符串[content]，[password]为密钥，
  ///[hex]设置输出格式为hex或base64
  static Future<String> hmacSHA256(String? content, String password, {bool hex = true}) async {
    if(isEmpty(content) || isEmpty(password)) return "";
    return await _get().invokeMethod('macsha256', {"content" : content, "password" : password, "hex" : hex});
  }

  ///使用 RSA 算法加密字符串[content]，[publickey]为加密公钥
  ///[hex]设置输出格式为hex或base64
  static Future<String> rsaEncrypt(String? content, String publickey, {bool hex = true}) async {
    if(isEmpty(content)) return "";
    return await _get().invokeMethod('rsaEncrypt', {"content" : content, "key" : publickey, "hex" : hex});
  }

  ///使用 RSA 算法解密字符串[content]，[privateKey]为解密私钥
  ///[hex]字符串格式为hex或base64
  static Future<String> rsaDecrypt(String? content, String privateKey, {bool hex = true}) async {
    if(isEmpty(content)) return "";
    return await _get().invokeMethod('rsaDecrypt', {"content" : content, "key" : privateKey, "hex" : hex});
  }

  static bool isEmpty(String? string) {
    return string == null || string.trim().isEmpty;
  }

  static MethodChannel _get() {
    _channel ??= const MethodChannel('com.jacky.util/crypto');
    return _channel!;
  }
}
